{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e6968fc2",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import time\n",
    "import numpy as np\n",
    "import sys\n",
    "from torch.utils.data import DataLoader\n",
    "\n",
    "notebook_dir = os.getcwd()\n",
    "project_root_path = os.path.dirname(notebook_dir)\n",
    "sys.path.insert(0, project_root_path)\n",
    "\n",
    "from src.config import PROJECT_ROOT\n",
    "\n",
    "from src.preprocessing import *\n",
    "from src.preprocessing.CUB import *\n",
    "from src.utils import get_filename_to_id_mapping\n",
    "from src import ImageConceptDataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9a496b8c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Found 11788 images.\n",
      "Processing in 369 batches of size 32 (for progress reporting)...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Processing batches: 100%|██████████| 369/369 [01:26<00:00,  4.25it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Finished processing.\n",
      "Successfully transformed: 11788 images.\n"
     ]
    }
   ],
   "source": [
    "# LOAD AND TRANSFORM IMAGES\n",
    "input_dir = os.path.join(PROJECT_ROOT, 'images', 'CUB')\n",
    "resol = 299\n",
    "training = True\n",
    "images_file = os.path.join(PROJECT_ROOT, 'data', 'CUB', 'images.txt')\n",
    "\n",
    "image_tensors, image_paths = load_and_transform_images(input_dir, images_file, resol, training, batch_size=32, verbose=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "4395dab6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Found 11788 unique images.\n",
      "Found 312 unique concepts.\n",
      "Generated concept matrix with shape: (11788, 312)\n"
     ]
    }
   ],
   "source": [
    "# CREATE CONCEPT LABELS MATRIX\n",
    "concept_labels_file = os.path.join(PROJECT_ROOT, 'data', 'CUB', 'image_concept_labels.txt')\n",
    "\n",
    "concept_labels, uncertainty_matrix = encode_image_concepts(concept_labels_file, verbose=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "6dfd0e43",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Found 200 classes.\n",
      "Found labels for 11788 images.\n",
      "Generated one-hot matrix with shape: (11788, 200)\n"
     ]
    }
   ],
   "source": [
    "# CREATE IMAGE LABELS MATRIX\n",
    "labels_file = os.path.join(PROJECT_ROOT, 'data', 'CUB', 'image_class_labels.txt')\n",
    "classes_file = os.path.join(PROJECT_ROOT, 'data', 'CUB', 'classes.txt')\n",
    "\n",
    "image_labels = one_hot_encode_labels(labels_file, classes_file, verbose=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "888411bc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Split complete: 5994 train images, 5794 test images.\n",
      "Train set size: 5994 tensors, 5994 concepts, 5994 labels\n",
      "Test set size:  5794 tensors, 5794 concepts, 5794 labels\n"
     ]
    }
   ],
   "source": [
    "# CREATE TRAIN TEST SPLIT USING TXT FILE\n",
    "split_file = os.path.join(PROJECT_ROOT, 'data', 'CUB', 'train_test_split.txt')\n",
    "\n",
    "split_data = split_datasets(split_file, concept_labels, image_labels, uncertainty_matrix, image_tensors)\n",
    "\n",
    "train_concepts = split_data['train_concepts']\n",
    "test_concepts = split_data['test_concepts']\n",
    "\n",
    "train_img_labels = split_data['train_img_labels']\n",
    "test_img_labels = split_data['test_img_labels']\n",
    "\n",
    "train_tensors = split_data['train_tensors']\n",
    "test_tensors = split_data['test_tensors']\n",
    "\n",
    "print(f\"Train set size: {len(train_tensors)} tensors, {train_concepts.shape[0]} concepts, {train_img_labels.shape[0]} labels\")\n",
    "print(f\"Test set size:  {len(test_tensors)} tensors, {test_concepts.shape[0]} concepts, {test_img_labels.shape[0]} labels\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "3f167513",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Analyzing attribute imbalance in the training set...\n",
      "Training set shape: 5994 samples, 312 attributes.\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt # For plotting histogram\n",
    "\n",
    "# --- Code to Analyze Attribute Imbalance ---\n",
    "\n",
    "print(\"\\nAnalyzing attribute imbalance in the training set...\")\n",
    "\n",
    "# Ensure train_concepts is a NumPy array\n",
    "if not isinstance(train_concepts, np.ndarray):\n",
    "    try:\n",
    "        train_concepts_np = np.array(train_concepts)\n",
    "        print(\"Converted train_concepts to NumPy array.\")\n",
    "    except Exception as e:\n",
    "        print(f\"Error: Could not convert train_concepts to NumPy array. Please ensure it's defined. Details: {e}\")\n",
    "        # Stop execution here or handle appropriately\n",
    "        raise ValueError(\"train_concepts is not a NumPy array or convertible.\")\n",
    "else:\n",
    "    train_concepts_np = train_concepts\n",
    "\n",
    "if train_concepts_np.ndim != 2:\n",
    "     raise ValueError(f\"Expected train_concepts_np to be 2D, but got shape {train_concepts_np.shape}\")\n",
    "\n",
    "num_train_samples, num_attributes = train_concepts_np.shape\n",
    "print(f\"Training set shape: {num_train_samples} samples, {num_attributes} attributes.\")\n",
    "\n",
    "attribute_imbalance_stats = []\n",
    "\n",
    "# --- Optional: Load attribute names for better readability ---"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "31faaa03",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Most Imbalanced Attributes (by % positive deviated from 50%):\n",
      "  Index 137 (has_eye_color::purple): 0.13% Positive (8/5994), Ratio Neg/Pos: 748.25\n",
      "  Index 271 (has_leg_color::green): 0.17% Positive (10/5994), Ratio Neg/Pos: 598.40\n",
      "  Index 142 (has_eye_color::green): 0.20% Positive (12/5994), Ratio Neg/Pos: 498.50\n",
      "  Index 141 (has_eye_color::olive): 0.22% Positive (13/5994), Ratio Neg/Pos: 460.08\n",
      "  Index 286 (has_bill_color::green): 0.23% Positive (14/5994), Ratio Neg/Pos: 427.14\n",
      "  Index 281 (has_bill_color::purple): 0.27% Positive (16/5994), Ratio Neg/Pos: 373.62\n",
      "  Index 108 (has_breast_color::purple): 0.30% Positive (18/5994), Ratio Neg/Pos: 332.00\n",
      "  Index 143 (has_eye_color::pink): 0.32% Positive (19/5994), Ratio Neg/Pos: 314.47\n",
      "  Index 270 (has_leg_color::olive): 0.32% Positive (19/5994), Ratio Neg/Pos: 314.47\n",
      "  Index 200 (has_belly_color::purple): 0.33% Positive (20/5994), Ratio Neg/Pos: 298.70\n"
     ]
    }
   ],
   "source": [
    "attribute_names = []\n",
    "concept_names_path = os.path.join(PROJECT_ROOT, 'data', 'CUB', 'concepts.txt')\n",
    "with open(concept_names_path, 'r') as f:\n",
    "    attribute_names = [line.strip().split()[-1] for line in f] # Assumes format \"idx name\"\n",
    "\n",
    "# --------------------------------------------------------------\n",
    "\n",
    "for i in range(num_attributes):\n",
    "    attribute_column = train_concepts_np[:, i]\n",
    "\n",
    "    # Count occurrences of 0 and 1\n",
    "    counts = np.bincount(attribute_column.astype(int), minlength=2) # Ensures counts for 0 and 1 exist\n",
    "    num_neg = counts[0]\n",
    "    num_pos = counts[1]\n",
    "\n",
    "    # Calculate percentage positive\n",
    "    percent_pos = (num_pos / num_train_samples) * 100 if num_train_samples > 0 else 0\n",
    "\n",
    "    # Calculate ratio (handle division by zero)\n",
    "    ratio_neg_pos = num_neg / num_pos if num_pos > 0 else float('inf') # Negatives per Positive\n",
    "\n",
    "    attribute_imbalance_stats.append({\n",
    "        'index': i,\n",
    "        'name': attribute_names[i],\n",
    "        'num_pos': num_pos,\n",
    "        'num_neg': num_neg,\n",
    "        'percent_pos': percent_pos,\n",
    "        'ratio_neg_pos': ratio_neg_pos\n",
    "    })\n",
    "\n",
    "# --- Summarize the results ---\n",
    "\n",
    "# Sort by percentage positive (most skewed first)\n",
    "attribute_imbalance_stats.sort(key=lambda x: abs(x['percent_pos'] - 50), reverse=True)\n",
    "\n",
    "print(\"\\nMost Imbalanced Attributes (by % positive deviated from 50%):\")\n",
    "for k in range(min(10, num_attributes)): # Print top 10 most skewed\n",
    "    stats = attribute_imbalance_stats[k]\n",
    "    print(f\"  Index {stats['index']:<3d} ({stats['name']}): \"\n",
    "          f\"{stats['percent_pos']:.2f}% Positive ({stats['num_pos']}/{num_train_samples}), \"\n",
    "          f\"Ratio Neg/Pos: {stats['ratio_neg_pos']:.2f}\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "9b79d280",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Least Imbalanced Attributes (closest to 50%):\n",
      "  Index 218 (has_size::small_(5_-_9_in)): 51.25% Positive (3072/5994), Ratio Neg/Pos: 0.95\n",
      "  Index 235 (has_shape::perching-like): 48.57% Positive (2911/5994), Ratio Neg/Pos: 1.06\n",
      "  Index 54  (has_breast_pattern::solid): 55.21% Positive (3309/5994), Ratio Neg/Pos: 0.81\n",
      "  Index 289 (has_bill_color::black): 43.93% Positive (2633/5994), Ratio Neg/Pos: 1.28\n",
      "  Index 151 (has_bill_length::shorter_than_head): 56.17% Positive (3367/5994), Ratio Neg/Pos: 0.78\n",
      "  Index 20  (has_wing_color::black): 43.21% Positive (2590/5994), Ratio Neg/Pos: 1.31\n",
      "  Index 244 (has_belly_pattern::solid): 57.37% Positive (3439/5994), Ratio Neg/Pos: 0.74\n",
      "  Index 35  (has_upperparts_color::black): 39.02% Positive (2339/5994), Ratio Neg/Pos: 1.56\n",
      "  Index 51  (has_underparts_color::white): 38.96% Positive (2335/5994), Ratio Neg/Pos: 1.57\n",
      "  Index 6   (has_bill_shape::all-purpose): 38.05% Positive (2281/5994), Ratio Neg/Pos: 1.63\n"
     ]
    }
   ],
   "source": [
    "\n",
    "print(\"\\nLeast Imbalanced Attributes (closest to 50%):\")\n",
    "for k in range(min(10, num_attributes)): # Print top 10 least skewed\n",
    "    stats = attribute_imbalance_stats[-(k+1)]\n",
    "    print(f\"  Index {stats['index']:<3d} ({stats['name']}): \"\n",
    "          f\"{stats['percent_pos']:.2f}% Positive ({stats['num_pos']}/{num_train_samples}), \"\n",
    "          f\"Ratio Neg/Pos: {stats['ratio_neg_pos']:.2f}\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "dea98dac",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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6DdewZuo/qu+qewagaL9pN8xfZ5evXod8HWHDRvmjonaF9o2w4cPd0PodPLpQHTM1fxslUnfUT1Xw891HPd7sRS4XnHFFS7YV53U/tRvlOrJgdStW9f9r++B6l5evbY6Fuh3Qr/vKo/msmp763uo3wn97ug3UttL9UfHSpVVwqdE6GSbAkPtT/1mIwY8oBC8+OKL6kbxFixYkOs6lStX9k466aTQ/Xvuucc9x/f444+7+3/++Weur6HX1zp6v0hnnXWWe2z06NE5Pqabb8aMGW7dww8/3Nu6dWto+VtvveWWP/nkk6FldevW9bp163bA18yrbHq+Xsc3ceJEt+7999+fZb2///3vXkJCgrdixYrQMq2XkpKSZdnXX3/tlo8YMcLLyxNPPOHWe/XVV0PL9uzZ47Vs2dKrUKFCls+u8l188cV5vl74uueff77bV7qpPJ07d3bvdfPNN7t1evTo4dWsWdPbsGFDludqPdWFnTt3ZtkX9evXDy2Tffv2efXq1XPvtWnTpiyvkZmZGfq7devW3gknnODt3r07y+Onn366d8wxx2Sro23atMny/L59+3plypTxNm/eHFp2/PHHZ9m3Pr3H/v37syxbuXKll5qa6t13332hZY8++qh7L+1n365du7wGDRq45frMfjlVxrZt22Ypk7aDPvt5552Xx1743/fW6w0ePNjth7Vr13qffvqp+55p+TvvvOP2d40aNbzGjRu7MvgmT57s1hk0aJC7r22s+w8//HCe73kw9X7q1Klu3ffffz/LehdddJHb/75XXnnFS0xM9D777LMs6+m7refPmTMnzzLqfcuXL5/nOuF1zTd37lz3+i+//HK2etOsWTO3LX3Dhw93y9977z13f9u2bV6VKlW86667Lstrap+ovocvL8ixLy+XXHKJd8YZZ4TujxkzxktKSvLWr18fWqb6XbFiRa9FixZZ6oGE173cjqP5PZb06dPHq1Spkvv+5qZJkyb5PtZEWrdunftszz33XGiZvuvt2rXLsl5e9VLvHV4vfbkdi8If87+74dtK33dfRkaG17RpU/ed8+uLX4f0fT3Qa+ZWtvx+Jwpal/bu3et+e/r375/nejmVT/f1nlOmTMnX90zHu/Dve16/0Q0bNnTb1KffZi3/9ttvcz3O+MfFatWqeX/99Vdoub6rkccf/XYcccQR7vvr0zFU6+W0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CQkJWYbXKWj5888/7emnn7ZoUk9I8+bN7cEHHwy993fffWejR492gVRBqedMwVl4j5SGEOq9KlWqZLG0ePFiGzJkiKV1fdhS06KfvCOIjHXrbd2rQ2zOnDnWtGnTmJYFAAAAKAr+aLWoB1Lt27fPcj8xMdElgTj77LOtQYMGFk3KxNeoUaMsyxo2bGjvvPOO+zs9Pd39v27dOreuT/fzavinpqa6W6SkpCR3iyVtzz179tje/Z4lZv5fwBoLKoPKojLFersAAAAARSG/7d7AreN77rnHiooy9i1dujTLsmXLllndunVDiScUTE2fPj0UOCmC1DC0G264ocjKCQAAAKB0ietuhr59+9rpp5/uhvZdfvnl9sUXX9iYMWPcTTTEUOnY77//fjvmmGNC6c9r1aqVrecMAAAAAIo8kNLwrvC5UTnR49HM7nbKKafYhAkT3Jym++67zwVKSnfepUuX0Dq33XabmxDWs2dP27x5s7Vq1cpd04prSAEAAACIeSClgCY3SjWui+IqOUS0XXLJJe6WV/CmIEs3AAAAAIirQMq/4G04zV+644477P3333e9RAQzAAAAAEqDxII8ac2aNe6iuCeccIIbyqeU3S+99FIoCQQAAAAAlGSBAqktW7bY7bffbkcffbR9//33LlueeqMaN25ceCUEAAAAgOI6tG/48OH20EMPuXTjr7/+eo5D/QAAAACgNMh3IKW5UOXKlXO9URrGp1tO3n333WiWDwAAAACKbyB19dVXHzD9OQAAAACUBvkOpMaOHVu4JQEAAACAkpy1DwAAAABKMwIpAAAAAAiIQAoAAAAAAiKQAgAAAICACKQAAAAAICACKQAAAAAIiEAKAAAAAAIikAIAAACAgAikAAAAACAgAikAAAAACIhACgAAAAACIpACAAAAgIAIpAAAAAAgIAIpAAAAAAiIQAoAAAAAAiKQAgAAAICACKQAAAAAICACKQAAAAAIiEAKAAAAAAIikAIAAACAgAikAAAAACAgAikAAAAACIhACgAAAAACIpACAAAAgIAIpAAAAAAgIAIpAAAAACjJgdSwYcMsISHBbrnlltCy3bt3W69evaxatWpWoUIF69Spk61bty6m5QQAAABQshWbQGrBggX27LPP2oknnphled++fe3999+38ePH28yZM23NmjXWsWPHmJUTAAAAQMlXLAKp7du3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tU+oMwj3xRdfeElJSd4DDzzgLV++3Hvttde8Qw45xHv11VdD6wwbNsz9Lr333nveN99847Vr186rV6+et2vXrpiWHbHRrVs37/DDD/cmT57srVy50nv33Xe96tWre7fddltoHepM6bZt2zbvq6++cjeFHY899pj7+9dff813/bjgggu8k046yZs/f743e/Zsl4n2yiuv9OIBgVScGTFihGvYpKSkuHTo8+bNi3WREAd08Mnp9uKLL4bW0UHnxhtv9A499FDX+OnQoYMLtoDcAinqDCK9//77XuPGjd1JvQYNGnhjxozJ8rjSFQ8cONBLS0tz67Ru3dpbunRpzMqL2Nq6das7pqjdUrZsWa9+/freXXfd5WVkZITWoc6UbjNmzMix/aIgPL/1Y+PGjS5wqlChglepUiWve/fuLkCLBwn6J9a9YgAAAABQnDBHCgAAAAACIpACAAAAgIAIpAAAAAAgIAIpAAAAAAiIQAoAAAAAAiKQAgAAAICACKQAAAAAICACKQAAAAAIiEAKAFDs3HvvvZaWlmYJCQk2ceLEIn//s88+22655ZY81xk7dqxVqVLF4l00tuE111xj7du3P6jXGDhwoPXs2fOgXuOOO+6wm2+++aBeAwDyi0AKAKJADUk1SHVLSUmxo48+2u677z7bt2+fxbtYBSMFtWTJEhs8eLA9++yz9scff9iFF16YbZ1ffvkltD90q1atmp1//vn21VdfRaUM7777rg0ZMiR0/8gjj7QnnngiyzpXXHGFLVu2zArTp59+6j7f5s2brThbu3atPfnkk3bXXXeFlr322mtWu3ZtO/TQQ61fv37Z9u+xxx5rW7duzbL8P//5j7300kv2888/F1nZAZReBFIAECUXXHCBa9gvX77c+vfv73pNHn744QK91v79+y0zMzPqZSwJfvrpJ/d/u3btLD093VJTU3Nd9+OPP3b7ZOrUqbZ9+3YXdEUj6KhatapVrFgxz3XKlStnNWrUOOj3Kg3+53/+x04//XSrW7euu79hwwb717/+ZY888oh99NFH9uqrr9rkyZND69944402bNgwq1SpUpbXqV69urVt29aeeeaZIv8MAEofAikAiBI16NWwV2PwhhtusDZt2tikSZPcYxkZGe5s+eGHH27ly5e3Fi1auN6EyGFgWr9Ro0butVatWuWed/vtt7sz81qmnq7nn38+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",
      "text/plain": [
       "<Figure size 1000x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Analysis Complete.\n"
     ]
    }
   ],
   "source": [
    "\n",
    "# --- Plot Histogram of Percentage Positive ---\n",
    "all_percent_pos = [stats['percent_pos'] for stats in attribute_imbalance_stats]\n",
    "\n",
    "plt.figure(figsize=(10, 5))\n",
    "plt.hist(all_percent_pos, bins=20, range=(0, 100), edgecolor='black')\n",
    "plt.title('Distribution of Percentage Positive Labels Across Attributes (Training Set)')\n",
    "plt.xlabel('Percentage of Positive Labels (%)')\n",
    "plt.ylabel('Number of Attributes')\n",
    "plt.grid(axis='y', alpha=0.75)\n",
    "plt.show()\n",
    "\n",
    "print(\"\\nAnalysis Complete.\")\n",
    "# -------------------------------------------"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "eb988990",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
